from paste.httpexceptions import HTTPFound
from paste.request import construct_url

from zope.interface import implements

from repoze.who.interfaces import IMetadataProvider
from repoze.who.interfaces import IAuthenticator

from cibynet.model import utils as m_utils
from cibynet.model.m_users import User
from cibynet.model import m_failed_login_attempts


class UserModelPlugin(object):
    
    implements(IAuthenticator, IMetadataProvider)
     
    # IAuthenticator
    def authenticate(self, environ, identity):
        ip = environ['REMOTE_ADDR']
        if m_failed_login_attempts.isTemporized(ip):
            environ["FAILED_AUTHENTICATION"] = "True"
            environ["FAILED_AUTHENTICATION_TEMPORIZED"] = "True"
            return None
      
        try:
            username = identity['login']
            password = identity['password']
        except KeyError:
            return None
        
        user = m_utils.GetOneObject(User, username=username)
        if user is not None and user.validate_password(password):
          environ['repoze.who.application'] = HTTPFound(construct_url(environ))
          return str(user.id)
        
        # Authentication doesn't work: 
        # That won't necessary lead to a 401 response, all depends on the uper
        # layer of the WSGI stack.
        # FAILED_AUTHENTIFICATION will serve to feedback the user.
        environ["FAILED_AUTHENTICATION"] = True
        environ["FAILED_AUTHENTICATION_LOGIN"] = username
        environ["FAILED_AUTHENTICATION_PENALTY"] = \
                                      m_failed_login_attempts.add(ip, username)
        return None

    # IMetadataProvider
    def add_metadata(self, environ, identity):
        userid = identity.get('repoze.who.userid')
        user = m_utils.GetOneObject(User, id=userid)
        if user is not None:
            identity['user'] = user
            identity['groups'] = [g.name for g in user.groups]
            environ["REMOTE_USER_OBJ"] = user
